package myPackage;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

class Paths {

	/* ******************** DEVELOPER'S NOTES ********************
	 * If you want to read a file from inside your application use:
	 * InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
	 * The path starts with "/", but that is not the path in your file-system, but in your classpath. 
	 * So if your file is at the classpath "org.xml" and is called myxml.xml your path 
	 * looks like "/org/xml/myxml.xml".
	 * 
	 * The InputStream reads the content of your file. 
	 * You can wrap it into an Reader, if you want.

	  //TODO - 
	 * Convert error messages to dialog boxes
	 * *********************************************************** */

	private Paths() {}

	//TODO - change to classpath
	private static String WORKING_PATH = ".\\";

	public static String getWorkingPath() {
		return Paths.WORKING_PATH;
	}

	public static File getQuestions() {
		return new File(getWorkingPath().concat("xml\\questions.xml"));
	}

	public static File getUsers() {
		return new File(getWorkingPath().concat("xml\\users.xml"));
	}
	
	public static File getScoreSheet() {
		return new File(getWorkingPath().concat("scores\\"));
	}
	
}

class Player {

	private String USER;
	private Integer PID;
	
	private File xml;
	private Element root;
	
	/**
	 * Constructor
	 * */
	public Player() {}
	public Player(String User, Integer PID) {
		setOnlineUser(User, PID);
	}
	
	public void createNewUser(String Username, String Password, String firstName, String lastName) {

		root = new XMLProcessor(Paths.getUsers()).XMLReader().getDocumentElement();
		
		try {
			
			if (!isExisting(Username)) {
				//ALERTHERE
				System.out.println(Username + " is available!");
				System.out.println("Proceeding to create...");

				Element username = ((Document) root).createElement("username");
				Element password = ((Document) root).createElement("password");
				Element firstname = ((Document) root).createElement("firstname");
				Element lastname = ((Document) root).createElement("lastname");

				username.setTextContent(Username);
				password.setTextContent(Password);
				firstname.setTextContent(firstName);
				lastname.setTextContent(lastName);

				Element profile = ((Document) root).createElement("profile");
				profile.setAttribute("pid", String.valueOf(Integer.valueOf(Username)));

				profile.appendChild(username);
				profile.appendChild(password);
				profile.appendChild(firstname);
				profile.appendChild(lastname);

				root.appendChild(profile);

				root.replaceChild(root, root);

				Transformer tFormer = TransformerFactory.newInstance().newTransformer();
				tFormer.setOutputProperty(OutputKeys.METHOD, "xml");
				tFormer.setOutputProperty(OutputKeys.INDENT, "yes");
				tFormer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
				tFormer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

				Source source = new DOMSource(root);
				Result result = new StreamResult(Paths.getUsers());
				tFormer.transform(source, result);

				newScoreSheet(Integer.valueOf(Username));

				System.out.println("Finished creating new user novaed" + Username + "!");
			}


		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}

	}

	public void deleteUser(String Username, String Password) {

		NodeList userList = null;
		Node profile = null;

		Element username = null;

		try {

			Document xml = new XMLProcessor(Paths.getUsers()).XMLReader();
			userList = xml.getElementsByTagName("profile");

			for (int i = 0; i <= userList.getLength(); i++) {

				profile = userList.item(i);
				username = (Element) profile;

				if (username.getElementsByTagName("username").item(0)
						.getTextContent().equals("00073")) {

					profile.getParentNode().removeChild(profile);

					break;
				}

			}

			DOMSource XMLinput = new DOMSource(xml);
			StreamResult XMLoutput = new StreamResult(Paths.getUsers());
			new XMLProcessor().getTransformer().transform(XMLinput, XMLoutput);

		} catch (NullPointerException e) {
			System.err.println("User doesn't exist!");
		} catch (TransformerConfigurationException e) {
			System.err.println(e);
		} catch (TransformerException e) {
			System.err.println(e);
		}

	}
	
	public void setOnlineUser(String User, Integer PID) {
		this.USER = User;
		this.PID = PID;
	}

	public Integer getUserPID() {
		return this.PID;
	}
	
	public String getOnlineUser() {
		return this.USER;
	}
	
	/**
	 * Write a new empty XML file with the PID
	 * @param PID - The Integer value of the last five digits
	 * Player's NovaEd student number issued duly
	 * */
	public void newScoreSheet(int PID) {

		xml = new File(Paths.getScoreSheet() + "/" + getUserPID().toString() + ".xml");
		
		if (!xml.exists()) {

			/* trace message */
			System.err.println("newScoreSheet()");
			System.err.println(xml + " is not available!");
			System.err.println("Writing File...");
			
			new XMLProcessor().XMLWriter(xml);


		} else {
			//ALERTHERE
			System.out.println("yes");
		}

	}

	public File getScoreSheet() {
		
		xml = new File(Paths.getScoreSheet() + "/" + getUserPID().toString() + ".xml");

		try {
			
			if (!xml.exists()){

				/* trace message */
				//System.out.println("getScoreSheet()");
				//System.err.println("if ------- " + ScoreSheet.exists());

				//TODO alert dialog box
				//System.err.println(getUserPID() + "data file does not exist!");
				//System.err.println("Writing user datafile, please wait");
				
				newScoreSheet(getUserPID());
				
				//TODO
				// return to main profile screen
				
			}
			
		} catch (NullPointerException e) {
			System.err.println("** Class Name : Player");
			System.err.println("   Method Name : getScoreSheet()");
			System.err.println("   try/catch block: NullPointerException ");
			System.err.println("**");
		}

		return xml;
	}
	
	public boolean isExisting(String Username) {

		Element pid = null;

		NodeList profilesList = new XMLProcessor(Paths.getUsers()).XMLReader().getElementsByTagName("profile");

		for (int i = 0; i <= profilesList.getLength() - 1; i++) {
			Node profileNode = profilesList.item(i);
			pid = (Element) profileNode;

			if (pid.getAttribute("pid").equals(String.valueOf(Integer.valueOf(Username)))) {
				System.err.println(Username + " already exists!");
				return true;
			}

		}
		
		return false;
	}

	public boolean isOnline() {
		
		if (getOnlineUser() == null) {
			return false;
		}
		
		return true;
	}

}

class Profile extends Player {

	private String User;
	private Integer PID;
	
	private File ScoreSheet;
	
	protected BufferedReader br;
	protected ArrayList<Integer> arrayOfScores;

	public Profile() {}
	public Profile(String User, Integer PID) {
		super(User, PID);
		User = this.User;
		PID = this.PID;
	}

	/**
	 * @Override
	 * */
	public File getScoreSheet() {
		
		ScoreSheet = new File(Paths.getScoreSheet() + "/" + getUserPID().toString() + ".xml");
		XMLProcessor proc = new XMLProcessor(ScoreSheet);

		Node item = null;
		Element detail = null;

		NodeList quizzes = proc.XMLReader().getElementsByTagName("quiz");

		for (int i = 0; i <= quizzes.getLength() - 1; i++) {

			item = quizzes.item(i);
			detail = (Element) item;

			System.out.println("quiz# : " + detail.getAttribute("id"));
			System.out.println("date : "  + detail.getAttribute("date"));
			System.out.println("score : " + detail.getAttribute("score"));

		}
		
		return ScoreSheet;
				
	}
	
	public ArrayList<Integer> getScores() {

		String rawScore;
		arrayOfScores = new ArrayList<Integer>();

		try {
			
				br = new BufferedReader(new FileReader(getScoreSheet()));
				
				
				while ((rawScore = br.readLine()) != null) {
					arrayOfScores.add(Integer.parseInt(rawScore));
				}

			br.close();

		} catch (IOException e) {
			System.err.println("** Class Name : Profile");
			System.err.println("   Method Name : getScores()");
			System.err.println("   try/catch block: IOException");
			System.err.println("**");
//			System.err.println(Paths.getScoreSheet().toString() + " doesn't exist.");

		} catch (NullPointerException e) {
			System.err.println("** Class Name : Profile");
			System.err.println("   Method Name : getScores()");
			System.err.println("   try/catch block: NullPointerException ");
			System.err.println("**");
//			System.err.println(Paths.getScoreSheet().toString() + " doesn't exist.");
//			System.err.println(Paths.getScore().concat(String.valueOf(getUserPID())) + ".txt does not exist.");
		}

		return arrayOfScores;

	}

	public int getTimesPlayed() {

		return arrayOfScores.size();

	}

	public int getTotalScore() {
		int total = 0;

		for (int i = 0; i <= getTimesPlayed()-1; i++) 
			total+=arrayOfScores.get(i);

		return total;

	}

	public double getPercentage() {
		
		// 1. totalRawScore = n1, n2, n3, ...nn
		// 2. pct = 15 * nn
		// 3. totalPCT = (totalRawScore / pct) * 100
		return Double.valueOf(arrayOfScores.get(0));

	}
}